/**
 * @file iec104_controller_config.c
 * @brief IEC 104协议控制器配置管理模块实现
 * @details 加载和管理IEC 104控制器应用的配置参数
 * 
 * @author zyb
 * @date 2025-10-30
 * @version 1.0
 */

#include "../include/iec104_controller_config.h"
#include "../../../../common/logs/include/logger.h"
#include "../../../../common/config/include/cfg_utils.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 日志模块名称
#define LOG_MODULE_NAME "IEC104_CONTROLLER_CONFIG"

/* ==================== 辅助函数 ==================== */

/**
 * @brief 安全的字符串复制函数（避免strncpy截断警告）
 */
static inline void safe_strncpy(char *dest, const char *src, size_t dest_size) {
    if (dest == NULL || src == NULL || dest_size == 0) {
        return;
    }
    size_t src_len = strlen(src);
    size_t copy_len = (src_len < dest_size - 1) ? src_len : (dest_size - 1);
    memcpy(dest, src, copy_len);
    dest[copy_len] = '\0';
}

/* ==================== 默认配置值 ==================== */

#define DEFAULT_DEVICE_PORT 2404
#define DEFAULT_CONNECT_TIMEOUT 10
#define DEFAULT_T1_TIMEOUT 15
#define DEFAULT_T2_TIMEOUT 10
#define DEFAULT_T3_HEARTBEAT 20
#define DEFAULT_K_SEND_MAX 12
#define DEFAULT_W_RECEIVE_MAX 8
#define DEFAULT_COMMON_ADDRESS 1
#define DEFAULT_CAUSE_SIZE 2
#define DEFAULT_ASDU_ADDR_SIZE 2
#define DEFAULT_IOA_SIZE 3

/**
 * @brief 加载IEC 104控制器配置
 */
int iec104_controller_config_load(iec104_controller_config_t* config, const char* config_file) {
    if (config == NULL || config_file == NULL) {
        LOG_ERROR(LOG_MODULE_NAME, "配置参数为空");
        return -1;
    }
    
    LOG_INFO(LOG_MODULE_NAME, "加载配置文件: %s", config_file);
    
    // 初始化配置结构
    memset(config, 0, sizeof(iec104_controller_config_t));
    
    // 设置默认值
    config->device_port = DEFAULT_DEVICE_PORT;
    config->connect_timeout = DEFAULT_CONNECT_TIMEOUT;
    config->t1_timeout = DEFAULT_T1_TIMEOUT;
    config->t2_timeout = DEFAULT_T2_TIMEOUT;
    config->t3_heartbeat = DEFAULT_T3_HEARTBEAT;
    config->k_send_max = DEFAULT_K_SEND_MAX;
    config->w_receive_max = DEFAULT_W_RECEIVE_MAX;
    config->common_address = DEFAULT_COMMON_ADDRESS;
    config->cause_size = DEFAULT_CAUSE_SIZE;
    config->asdu_addr_size = DEFAULT_ASDU_ADDR_SIZE;
    config->ioa_size = DEFAULT_IOA_SIZE;
    
    // 打开配置文件
    FILE* fp = fopen(config_file, "r");
    if (fp == NULL) {
        LOG_ERROR(LOG_MODULE_NAME, "无法打开配置文件: %s", config_file);
        return -1;
    }
    
    char line[1024];
    int line_num = 0;
    
    while (fgets(line, sizeof(line), fp)) {
        line_num++;
        
        // 去除首尾空白字符
        char* p = line;
        while (*p == ' ' || *p == '\t') p++;
        if (*p == '\0' || *p == '\n' || *p == '#') {
            continue; // 空行或注释行
        }
        
        // 解析键值对
        char key[128], value[512];
        if (sscanf(p, "%127[^=]=%511[^\n]", key, value) != 2) {
            continue; // 跳过无效行
        }
        
        // 去除键和值的首尾空白
        char* key_end = key + strlen(key) - 1;
        while (key_end > key && (*key_end == ' ' || *key_end == '\t')) {
            *key_end = '\0';
            key_end--;
        }
        
        char* value_start = value;
        while (*value_start == ' ' || *value_start == '\t') value_start++;
        char* value_end = value_start + strlen(value_start) - 1;
        while (value_end > value_start && (*value_end == ' ' || *value_end == '\t' || *value_end == '\n')) {
            *value_end = '\0';
            value_end--;
        }
        
        // 解析104配置项
        if (strcmp(key, "device_ip") == 0) {
            safe_strncpy(config->device_ip, value_start, sizeof(config->device_ip));
        } else if (strcmp(key, "device_port") == 0) {
            config->device_port = (uint16_t)atoi(value_start);
        } else if (strcmp(key, "connect_timeout") == 0) {
            config->connect_timeout = atoi(value_start);
        } else if (strcmp(key, "t1_timeout") == 0) {
            config->t1_timeout = atoi(value_start);
        } else if (strcmp(key, "t2_timeout") == 0) {
            config->t2_timeout = atoi(value_start);
        } else if (strcmp(key, "t3_heartbeat") == 0) {
            config->t3_heartbeat = atoi(value_start);
        } else if (strcmp(key, "k_send_max") == 0) {
            config->k_send_max = atoi(value_start);
        } else if (strcmp(key, "w_receive_max") == 0) {
            config->w_receive_max = atoi(value_start);
        } else if (strcmp(key, "common_address") == 0) {
            config->common_address = atoi(value_start);
        } else if (strcmp(key, "cause_size") == 0) {
            config->cause_size = atoi(value_start);
        } else if (strcmp(key, "asdu_addr_size") == 0) {
            config->asdu_addr_size = atoi(value_start);
        } else if (strcmp(key, "ioa_size") == 0) {
            config->ioa_size = atoi(value_start);
        }
    }
    
    fclose(fp);
    
    LOG_DEBUG(LOG_MODULE_NAME, "配置加载完成");
    return 0;
}

/**
 * @brief 打印IEC 104控制器配置
 */
void iec104_controller_config_print(const iec104_controller_config_t* config) {
    if (config == NULL) {
        LOG_ERROR(LOG_MODULE_NAME, "配置为空");
        return;
    }
    
    LOG_DEBUG(LOG_MODULE_NAME, "==================== IEC 104控制器配置 ====================");
    LOG_DEBUG(LOG_MODULE_NAME, "TCP连接配置:");
    LOG_DEBUG(LOG_MODULE_NAME, "  设备IP地址: %s", config->device_ip);
    LOG_DEBUG(LOG_MODULE_NAME, "  设备端口: %u", config->device_port);
    LOG_DEBUG(LOG_MODULE_NAME, "  连接超时: %d秒", config->connect_timeout);
    
    LOG_DEBUG(LOG_MODULE_NAME, "APDU参数:");
    LOG_DEBUG(LOG_MODULE_NAME, "  T1超时: %d秒", config->t1_timeout);
    LOG_DEBUG(LOG_MODULE_NAME, "  T2超时: %d秒", config->t2_timeout);
    LOG_DEBUG(LOG_MODULE_NAME, "  T3心跳: %d秒", config->t3_heartbeat);
    LOG_DEBUG(LOG_MODULE_NAME, "  K值(最大未确认发送): %d", config->k_send_max);
    LOG_DEBUG(LOG_MODULE_NAME, "  W值(最大未确认接收): %d", config->w_receive_max);
    
    LOG_DEBUG(LOG_MODULE_NAME, "ASDU参数:");
    LOG_DEBUG(LOG_MODULE_NAME, "  公共地址: %d", config->common_address);
    LOG_DEBUG(LOG_MODULE_NAME, "  传输原因字节数: %d", config->cause_size);
    LOG_DEBUG(LOG_MODULE_NAME, "  ASDU地址字节数: %d", config->asdu_addr_size);
    LOG_DEBUG(LOG_MODULE_NAME, "  信息对象地址字节数: %d", config->ioa_size);
    LOG_DEBUG(LOG_MODULE_NAME, "========================================================");
}

/**
 * @brief 验证IEC 104控制器配置
 */
int iec104_controller_config_validate(const iec104_controller_config_t* config) {
    if (config == NULL) {
        LOG_ERROR(LOG_MODULE_NAME, "配置为空");
        return -1;
    }
    
    // 验证设备IP地址
    if (strlen(config->device_ip) == 0) {
        LOG_ERROR(LOG_MODULE_NAME, "设备IP地址为空");
        return -1;
    }
    
    // 验证设备端口
    if (config->device_port == 0) {
        LOG_ERROR(LOG_MODULE_NAME, "设备端口无效: %u", config->device_port);
        return -1;
    }
    
    // 验证超时参数
    if (config->connect_timeout <= 0) {
        LOG_ERROR(LOG_MODULE_NAME, "连接超时时间无效: %d", config->connect_timeout);
        return -1;
    }
    
    if (config->t1_timeout <= 0 || config->t1_timeout > 255) {
        LOG_ERROR(LOG_MODULE_NAME, "T1超时时间无效: %d", config->t1_timeout);
        return -1;
    }
    
    if (config->t2_timeout <= 0 || config->t2_timeout > 255) {
        LOG_ERROR(LOG_MODULE_NAME, "T2超时时间无效: %d", config->t2_timeout);
        return -1;
    }
    
    if (config->t3_heartbeat <= 0 || config->t3_heartbeat > 65535) {
        LOG_ERROR(LOG_MODULE_NAME, "T3心跳时间无效: %d", config->t3_heartbeat);
        return -1;
    }
    
    // 验证APDU参数
    if (config->k_send_max <= 0 || config->k_send_max > 32767) {
        LOG_ERROR(LOG_MODULE_NAME, "K值无效: %d", config->k_send_max);
        return -1;
    }
    
    if (config->w_receive_max <= 0 || config->w_receive_max > 32767) {
        LOG_ERROR(LOG_MODULE_NAME, "W值无效: %d", config->w_receive_max);
        return -1;
    }
    
    // 验证ASDU参数
    if (config->common_address < 0 || config->common_address > 65535) {
        LOG_ERROR(LOG_MODULE_NAME, "公共地址无效: %d", config->common_address);
        return -1;
    }
    
    if (config->cause_size != 1 && config->cause_size != 2) {
        LOG_ERROR(LOG_MODULE_NAME, "传输原因字节数无效: %d (必须为1或2)", config->cause_size);
        return -1;
    }
    
    if (config->asdu_addr_size != 1 && config->asdu_addr_size != 2) {
        LOG_ERROR(LOG_MODULE_NAME, "ASDU地址字节数无效: %d (必须为1或2)", config->asdu_addr_size);
        return -1;
    }
    
    if (config->ioa_size != 1 && config->ioa_size != 2 && config->ioa_size != 3) {
        LOG_ERROR(LOG_MODULE_NAME, "信息对象地址字节数无效: %d (必须为1, 2或3)", config->ioa_size);
        return -1;
    }
    
    LOG_INFO(LOG_MODULE_NAME, "配置验证通过");
    return 0;
}
